﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Com.Binaria.Core.Attribute;
using Com.Binaria.SISCOB.DTO;
using System.IO;
using Com.Binaria.Core.Base;
using Com.Binaria.SISCOB.Funcional.DTO;
using Com.Binaria.Core.Exceptions;
using Com.Binaria.Core;
using System.Diagnostics;
using System.Collections;
using Com.Binaria.Core.Util;
using Com.Binaria.SISCOB.Dom;

namespace Com.Binaria.SISCOB.Mgr
{
    public class ImportarDocumentoMgr : IImportarDocumentoMgr
    {
        #region Public Fields

        public ICartolaDom iCartolaDom;
        public ICuentaCorrienteDom iCuentaCorrienteDom;
        public ISucursalDom iSucursalDom;
        public IItemCartolaDom iItemCartolaDom;

        public IConstante iConstante;
        public IEgresoDom iEgresoDom;
        public IIngresoDom iIngresoDom;

        public ICartolaMayorDom iCartolaMayorDom;
        public IRegistroContableDom iRegistroContableDom;

        #endregion

        #region Miembros de IImportarArchivoMgr

        //[TrasanctionAttribute(TransactionScopeOption.Required)]
        public string Importar(string dirPath, string tipo)
        {
            StringBuilder sbLog = new StringBuilder();
            if (!Directory.Exists(dirPath)) return string.Empty;
            //
            object oImporter = FactoryImpl.getInstance().getObject(string.Format("Importar{0}", tipo.ToUpper()));

            //====================================================================
            //  Tipo: Cartola Bancaria (CB)
            //====================================================================
            if (string.Compare("CB", tipo, StringComparison.OrdinalIgnoreCase) == 0)
            {
                return ImportarCB(oImporter as IImportarCB, dirPath);
            }
            else if (string.Compare("RC", tipo, StringComparison.OrdinalIgnoreCase) == 0)
            {
                return ImportarRC(oImporter as IImportarRC, dirPath);
            }

            //
            return sbLog.ToString();
        }

        #endregion

        #region Private Methods

        string ImportarRC(IImportarRC oRC, string dirPath)
        {
            if (oRC == null)
                throw new ManagerException(Factoria.GetMessage("MGR_NO_INSTANCE"), TraceEventType.Warning);
            //Informar actividad en proceso
            StringBuilder sbLog = new StringBuilder();
            sbLog.AppendLine("Importar - Registro Contable");
            //Verificar la existencia del Path
            DirectoryInfo oDir = new DirectoryInfo(dirPath);
            if (!oDir.Exists) throw new ManagerException(Factoria.GetMessage("MGR_RC_NOEXIST"), TraceEventType.Warning);
            //Recuperar lista de ficheros .csv
            FileInfo[] aFiles = oDir.GetFiles("*.csv", SearchOption.TopDirectoryOnly);
            ArrayList oLst = new ArrayList(aFiles.Length);
            //Procesar cada uno de los archivos encontrados
            for (int i = 0; i < aFiles.Length; i++)
            {
                sbLog.AppendLine(string.Format("Procesando Archivo : {0}", aFiles[i].Name));
                //
                try
                {
                    RegistroContableDTO[] oRegistros = oRC.Cargar(aFiles[i].FullName);
                    if (oRegistros != null && oRegistros.Length > 0)
                    {
                        //Buscar la Informacion
                        List<CartolaMayorDTO> oFind = iCartolaMayorDom.BuscarCartolaMayorFiltro(new ContextoDTO()
                                                            , new CartolaMayorDTO()
                                                            {
                                                                FchDesde = oRegistros[0].CartolaMayor.FchDesde,
                                                                IdCuentaCorriente = oRegistros[0].CartolaMayor.IdCuentaCorriente
                                                            });
                        if (oFind.Count != 0)
                        {
                            sbLog.AppendLine(string.Format("  Folio: {0} [No Existe]", oRegistros[0].NmrDcto));
                            //throw new ManagerException(Factoria.GetMessage("MGR_CARTOLA_EXIST"), TraceEventType.Warning);
                        }
                        else
                        {
                            long totMonto = oRegistros.Sum(a => (long)a.Monto);
                            sbLog.AppendLine(string.Format("  Monto Importado: {0}", totMonto));

                            //Agrupar informacion
                            totMonto = 0;
                            Hashtable oTable = new Hashtable(16);
                            for (int k = 0; k < oRegistros.Length; k++)
                            {
                                string sKey = string.Concat(oRegistros[k].FchRegistro, oRegistros[k].Monto, oRegistros[k].NmrDcto, oRegistros[k].NmrAsiento);
                                if (oTable.ContainsKey(sKey))
                                {
                                    RegistroContableDTO oTmp = oTable[sKey] as RegistroContableDTO;
                                    oTmp.Monto += oRegistros[k].Monto;
                                }
                                else
                                {
                                    oTable.Add(sKey, oRegistros[k]);
                                }
                                //
                                totMonto += (long)oRegistros[k].Monto;
                            }
                            //
                            RegistroContableDTO[] tmpDTO = new RegistroContableDTO[oTable.Values.Count];
                            oTable.Values.CopyTo(tmpDTO, 0);
                            //Registrar informacion relacionada
                            RegistroContableDTO[] aDTO = SaveItemsRC(tmpDTO);
                            sbLog.AppendLine(string.Format("  Registros: {0} \t-> Monto: {1}", aDTO.Length, totMonto));
                            //
                            DocumentoTransaccionDTO[] aDOC = ParseDocumentoTransaccion(aDTO);
                            SaveDocumentoTransaccion(aDOC);
                            sbLog.AppendLine(string.Format("  Documentos: {0} \t-> Monto: {1}", aDOC.Length, aDOC.Sum(a => (long)a.Monto)));
                            //
                            sbLog.AppendLine(string.Format("  Folio: {0} [OK]", aDTO[0].NmrDcto));
                        }
                    }
                    File.Move(aFiles[i].FullName, string.Format("{0}.bkp", aFiles[i].FullName));
                }
                catch (Exception ex)
                {
                    sbLog.AppendLine(string.Format("Procesando Archivo : {0} [BAD] ({1})", aFiles[i].Name, ex.Message));
                }
            }
            //
            return sbLog.ToString();
        }

        string ImportarCB(IImportarCB oCB, string dirPath)
        {
            if (oCB == null)
                throw new ManagerException(Factoria.GetMessage("MGR_NO_INSTANCE"), TraceEventType.Warning);
            //Informar actividad en proceso
            StringBuilder sbLog = new StringBuilder();
            sbLog.AppendLine("Importar - Modalidad Cartolas");
            //Verificar la existencia del Path
            DirectoryInfo oDir = new DirectoryInfo(dirPath);
            if (!oDir.Exists) throw new ManagerException(Factoria.GetMessage("MGR_CB_NOEXIST"), TraceEventType.Warning);
            //Recuperar lista de ficheros .csv
            FileInfo[] aFiles = oDir.GetFiles("*.csv", SearchOption.TopDirectoryOnly);
            ArrayList oLst = new ArrayList(aFiles.Length);
            //Procesar cada uno de los archivos encontrados
            for (int i = 0; i < aFiles.Length; i++)
            {
                sbLog.AppendLine(string.Format("Procesando Archivo : {0}", aFiles[i].Name));
                //
                try
                {
                    ItemCartolaDTO[] oCartolas = oCB.Cargar(aFiles[i].FullName);
                    if (oCartolas != null && oCartolas.Length > 0)
                    {
                        //Buscar la Informacion
                        List<CartolaDTO> oFind = iCartolaDom.BuscarCartolaFiltro(new ContextoDTO()
                                                            , new CartolaDTO()
                                                            {
                                                                Folio = oCartolas[0].Cartola.Folio,
                                                                IdCuentaCorriente = oCartolas[0].Cartola.IdCuentaCorriente,
                                                                FchEmision = oCartolas[0].Cartola.FchEmision
                                                            });
                        if (oFind.Count != 0)
                        {
                            sbLog.AppendLine(string.Format("  Folio: {0} [No Existe]", oCartolas[0].Cartola.Folio));
                            //throw new ManagerException(Factoria.GetMessage("MGR_CARTOLA_EXIST"), TraceEventType.Warning);
                        }
                        else
                        {
                            long totMonto = oCartolas.Sum(a => (long)a.Monto);

                            //Registrar informacion relacionada
                            ItemCartolaDTO[] aDTO = SaveItemsCB(oCartolas);
                            sbLog.AppendLine(string.Format("  Cartolas: {0} \t-> Monto: {1}", aDTO.Length, totMonto));
                            //
                            DocumentoTransaccionDTO[] aDOC = ParseDocumentoTransaccion(aDTO);
                            SaveDocumentoTransaccion(aDOC);
                            sbLog.AppendLine(string.Format("  Documentos: {0} \t-> Monto: {1}", aDOC.Length, aDOC.Sum(a => (long)a.Monto)));
                            //
                            sbLog.AppendLine(string.Format("  Folio: {0} [OK]", oCartolas[0].Cartola.Folio));
                        }
                    }
                    File.Move(aFiles[i].FullName, string.Format("{0}.bkp", aFiles[i].FullName));
                }
                catch (Exception ex)
                {
                    sbLog.AppendLine(string.Format("Procesando Archivo : {0} [BAD] ({1})", aFiles[i].Name, ex.Message));
                }
            }
            //
            return sbLog.ToString();
        }


        ItemCartolaDTO[] SaveItemsCB(ItemCartolaDTO[] items)
        {
            ArrayList oLst = new ArrayList(16);

            for (int i = 0; i < items.Length; i++)
            {
                items[i].Cartola.CuentaCorriente = iCuentaCorrienteDom.ProbarRegistrar(new ContextoDTO(), items[i].Cartola.CuentaCorriente);
                items[i].Cartola.IdCuentaCorriente = items[i].Cartola.CuentaCorriente.Id;

                items[i].Cartola = iCartolaDom.ProbarRegistrar(new ContextoDTO(), items[i].Cartola);
                items[i].IdCartola = items[i].Cartola.Id;

                items[i].Sucursal = iSucursalDom.ProbarRegistrar(new ContextoDTO(), items[i].Sucursal);
                items[i].IdSucursal = items[i].Sucursal.Id;

                oLst.Add(iItemCartolaDom.ProbarRegistrar(new ContextoDTO(), items[i]));
            }
            //
            return (ItemCartolaDTO[])oLst.ToArray(typeof(ItemCartolaDTO));
        }

        RegistroContableDTO[] SaveItemsRC(RegistroContableDTO[] items)
        {
            ArrayList oLst = new ArrayList(16);

            for (int i = 0; i < items.Length; i++)
            {
                items[i].CartolaMayor.CuentaCorriente = iCuentaCorrienteDom.ProbarRegistrar(new ContextoDTO(), items[i].CartolaMayor.CuentaCorriente);
                items[i].CartolaMayor.IdCuentaCorriente = items[i].CartolaMayor.CuentaCorriente.Id;

                items[i].CartolaMayor = iCartolaMayorDom.ProbarRegistrar(new ContextoDTO(), items[i].CartolaMayor);
                items[i].IdCartolaMayor = items[i].CartolaMayor.Id;

                oLst.Add(iRegistroContableDom.ProbarRegistrar(new ContextoDTO(), items[i]));
            }
            //
            return (RegistroContableDTO[])oLst.ToArray(typeof(RegistroContableDTO));
        }

        DocumentoTransaccionDTO[] ParseDocumentoTransaccion(ItemCartolaDTO[] items)
        {
            ArrayList oLst = new ArrayList(16);
            //
            for (int i = 0; i < items.Length; i++)
            {
                DocumentoTransaccionDTO oDoc = new DocumentoTransaccionDTO();
                //
                oDoc.IdCuentaCorriente = items[i].Cartola.IdCuentaCorriente;
                oDoc.IdSucursal = items[i].IdSucursal;
                oDoc.Monto = items[i].Monto;
                oDoc.FchDocumento = items[i].FchOperacion;
                oDoc.FchUpdate = DateTime.Now;
                oDoc.Glosa = items[i].DscOperacion;
                oDoc.NmrDocumento = items[i].NmrOperacion;
                oDoc.UserName = iConstante.getValue("UsrSystem");
                oDoc.EstaActivo = true;

                if (items[i].Tipo.Equals("C"))
                {
                    // Se crea DocumentoTransaccion (Egreso)
                    oDoc.Egreso = new EgresoDTO();
                    oDoc.Egreso.EsManual = false;
                    oDoc.Egreso.Estado = "ON";
                }
                else if (items[i].Tipo.Equals("A"))
                {
                    // Se crea DocumentoTransaccion (Ingreso)
                    oDoc.Ingreso = new IngresoDTO();
                    oDoc.Ingreso.Tipo = "SN";
                    oDoc.Ingreso.Estado = "OB";
                }
                //
                oLst.Add(oDoc);
            }
            //
            return (DocumentoTransaccionDTO[])oLst.ToArray(typeof(DocumentoTransaccionDTO));
        }

        DocumentoTransaccionDTO[] ParseDocumentoTransaccion(RegistroContableDTO[] items)
        {
            long tot = 0;
            //
            StringBuilder sbKey = new StringBuilder(16);
            Hashtable oTable = new Hashtable(16);
            //
            for (int i = 0; i < items.Length; i++)
            {
                sbKey.Length = 0;
                tot = 0;
                //
                DocumentoTransaccionDTO oDTO = new DocumentoTransaccionDTO();
                List<RegistroContableDTO> oLstResult = null;
                //
                if (items[i].Tipo.Equals("E"))
                {
                    oLstResult = iRegistroContableDom.BuscarRegistroContableByEgreso(new ContextoDTO(), items[i]);
                    sbKey.Append(string.Concat(items[i].CartolaMayor.IdCuentaCorriente, ";", items[i].NmrDcto));
                    // Se crea DocumentoTransaccion (Egreso)
                    oDTO.Egreso = new EgresoDTO();
                    oDTO.Egreso.EsManual = false;
                    oDTO.Egreso.Estado = "GI";  // Egreso Girado
                }
                else if (items[i].Tipo.Equals("I"))
                {
                    oLstResult = iRegistroContableDom.BuscarRegistroContableByIngreso(new ContextoDTO(), items[i]);
                    sbKey.Append(string.Concat(items[i].CartolaMayor.IdCuentaCorriente, ";", items[i].FchRegistro, ";", items[i].Monto));
                    // Se crea DocumentoTransaccion (Ingreso)
                    oDTO.Ingreso = new IngresoDTO();
                    oDTO.Ingreso.Tipo = "SN";
                    oDTO.Ingreso.Estado = "RE";  // Ingreso Registrado
                }
                //
                oDTO.Monto = oLstResult.Sum(a => (long)a.Monto);
                //
                if (!oTable.ContainsKey(sbKey.ToString()) && oDTO.Monto != 0)
                {
                    oDTO.IdCuentaCorriente = items[i].CartolaMayor.IdCuentaCorriente;
                    oDTO.FchDocumento = items[i].FchRegistro;
                    oDTO.FchUpdate = DateTime.Now;
                    oDTO.Glosa = items[i].Glosa;
                    oDTO.NmrDocumento = items[i].NmrDcto;
                    oDTO.UserName = iConstante.getValue("UsrSystem");
                    oDTO.EstaActivo = true;
                    //
                    oTable.Add(sbKey.ToString(), oDTO);
                }
            }
            //
            DocumentoTransaccionDTO[] tmpDTO = new DocumentoTransaccionDTO[oTable.Values.Count];
            oTable.Values.CopyTo(tmpDTO, 0);
            //
            return tmpDTO;
        }

        DocumentoTransaccionDTO[] SaveDocumentoTransaccion(DocumentoTransaccionDTO[] items)
        {
            ArrayList oLst = new ArrayList(16);
            //
            for (int i = 0; i < items.Length; i++)
            {
                DocumentoTransaccionDTO oDoc = new DocumentoTransaccionDTO();
                //
                if (items[i].Egreso != null)
                    oDoc.Egreso = iEgresoDom.ProbarRegistrar(new ContextoDTO(), items[i]);
                else if (items[i].Ingreso != null)
                    oDoc.Ingreso = iIngresoDom.ProbarRegistrar(new ContextoDTO(), items[i]);
                //
                oLst.Add(oDoc);
            }
            return (DocumentoTransaccionDTO[])oLst.ToArray(typeof(DocumentoTransaccionDTO));
        }

        #endregion
    }
}
